package com.link.base.base.accntconsumer.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link.base.base.accnt.DmpField;
import com.link.base.base.accnt.dao.mybatis.mapper.AcctAddressMapper;
import com.link.base.base.accnt.model.*;
import com.link.base.base.accnt.service.AcctAddressService;
import com.link.base.base.accntconsumer.dao.mybatis.mapper.AccountConsumerMapper;
import com.link.base.base.accntconsumer.model.AccountConsumer;
import com.link.base.base.consumer.model.PortalAccntTag;
import com.link.base.base.consumer.model.PortalAccntTagItem;
import com.link.base.base.consumer.service.PortalAccntTagItemService;
import com.link.base.base.consumer.service.PortalAccntTagService;
import com.link.base.base.mpconfig.model.Mp;
import com.link.base.base.mvg.dao.mybatis.accnt.mapper.AccntCompanyMvgMapper;
import com.link.base.base.mvg.dao.mybatis.accnt.mapper.AccntOrgMvgMapper;
import com.link.base.base.mvg.model.Mvg;
import com.link.base.base.user.service.UserService;
import com.link.base.core.RSAUtils.SecretKeyUtil;
import com.link.base.core.basic.util.YmlConstants;
import com.link.base.microinterface.cdcconsumer.CdcPubConsumerClient;
import com.link.base.user.model.CoreUser;
import com.link.base.wechat.wxsubscriber.model.Subscriber;
import com.link.base.wechat.wxsubscriber.service.WxSubscriberService;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.query.Filter;
import com.link.core.basic.service.*;
import com.link.core.cllog.LCLogger;
import com.link.core.util.*;
import com.link.core.util.redisclient.LinkRedisClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.InvalidAlgorithmParameterException;
import java.util.*;
import java.util.function.Predicate;

import static java.util.stream.Collectors.partitioningBy;
import static java.util.stream.Collectors.toList;

/**
 * 消费者
 *
 * @author 曲元涛
 * @date 2020-07-01 18:12:52
 */
@Service
public class AccountConsumerServiceImpl extends BasicServiceImpl<AccountConsumer> implements AccountConsumerService, InitializingBean {

    private static final Logger logger = LogManager.getLogger(AccountConsumerServiceImpl.class);

    @Resource
    private AccountConsumerMapper accountConsumerMapper;
    @Resource
    private UserService userService;
    @Resource
    private AccntOrgMvgMapper accntOrgMvgMapper;
    @Resource
    private AccntCompanyMvgMapper accntCompanyMvgMapper;
    @Resource
    private AcctAddressService acctAddressService;
    @Resource
    private WxSubscriberService wxSubscriberService;
    @Resource
    private CdcPubConsumerClient cdcPubConsumerClient;
    @Resource
    private PortalAccntTagItemService portalAccntTagItemService;
    @Resource
    private KeyGenerateService keyGenerateService;
    @Resource
    private AcctAddressMapper acctAddressMapper;
    @Resource
    private PortalAccntTagService portalAccntTagService;

    /**dmp新建消费者接口路径*/
    private static final String DMP_CONSUMER_INTERFACE_URL = "/link/cdcPubConsumer/upsert";
    /**消费者来源：营销平台*/
    private static final String SOURCE_CHANNEL_MARKET = "MarketingPlatform";
    /**消费者来源：微信*/
    private static final String SOURCE_CHANNEL_WE_CHAT = "WeChat";
    /**渠道：微信*/
    private static final String ACCOUNT_CHANNEL_MARKETING = "Marketing";
    /**消费者来源：微信*/
    private static final String ACCOUNT_CHANNEL_TYPE_MARKETING_PLATFORM = "MarketingPlatform";
    /**性别转换Map映射*/
    private final HashMap<String, String> genderMap = new HashMap<>(4);

    @Override
    public BasicMapper<AccountConsumer> getBasicMapper() {
        return accountConsumerMapper;
    }

    @Override
    public void beforInsert(AccountConsumer entity) throws Exception {
        if (StringUtils.isNotBlank(entity.getMobilePhone())) {
            AccountConsumer account = new AccountConsumer();
            account.setAcctChannel(entity.getAcctChannel());
            account.setMobilePhone(entity.getMobilePhone());
            List<AccountConsumer> resultList = this.queryConsumerByCondition(account);
            if (null != resultList && !resultList.isEmpty()) {
                throw new ServiceException("PUBLIC-011");
            }
        }
    }

    @Override
    public void afterInsert(AccountConsumer entity) throws Exception {
        // dmp调用后，存储组织与公司的MVG逻辑
        String uniqueConsumer = "UniqueConsumer";
        if (uniqueConsumer.equals(entity.getConsumerType())) {
            Mvg mvgEntity = new Mvg();
            mvgEntity.setId(keyGenerateService.keyGenerate());
            mvgEntity.setMvgParentId(entity.getId());
            mvgEntity.setMvgSubsetId(entity.getOrgId());
            accntOrgMvgMapper.insert(mvgEntity);
            // 组织与公司的关联
            mvgEntity.setId(keyGenerateService.keyGenerate());
            mvgEntity.setMvgSubsetId(entity.getCompanyId());
            accntCompanyMvgMapper.insert(mvgEntity);
        }
    }

    @Override
    public AccountConsumer queryUniqueByExample(AccountConsumer record) throws Exception {
        return accountConsumerMapper.queryUniqueByExample(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moreModelInsert(AccountConsumer accntline) throws Exception {
        CoreUser landedUser = UserUtil.getUser();
        //插入消费者
        if (StringUtils.isBlank(accntline.getFirstEngageTime())) {
            String engageTime = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
            accntline.setFirstEngageTime(engageTime);
        }
        accountConsumerMapper.insert(accntline);
        //插入消费者地址
        if (accntline.getAccntTagList() != null && !accntline.getAddrList().isEmpty()) {
            for (AcctAddress model : accntline.getAddrList()) {
                model.setAcctId(accntline.getId());
                model.setId(keyGenerateService.keyGenerate());
                acctAddressMapper.insert(model);
            }
        }
        //插入消费者标签
        if (accntline.getAccntTagList() != null && !accntline.getAccntTagList().isEmpty()) {
            for (PortalAccntTag model : accntline.getAccntTagList()) {
                model.setAccntRowId(accntline.getId());
                model.setOrgId(landedUser.getOrgId());
            }
            portalAccntTagService.batchUpsert(accntline.getAccntTagList());
        }
    }

    @Override
    public String getVirtualAccount(Long corpId) {
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            Map<String, String> privateCfg = jedis.hgetAll(RedisConstants.SYS_PROPERTY_CORP_KEY + corpId);
            String visualAccountID = privateCfg.get("VisualAccountID");
            return StringUtils.isNotBlank(visualAccountID) ? visualAccountID : "";
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    @Override
    public AccountConsumer checkAccount(AccountConsumer accountConsumer) throws Exception {
        CoreUser user = UserUtil.getUser();
        AccountConsumer queryParam = new AccountConsumer();
        queryParam.setPageFlag(false);
        queryParam.setCorpid(user.getCorpid());
        queryParam.setOrgId(user.getOrgId());
        // 原来是queryParam.setMobilePhone1(account.getMobilePhone1());
        queryParam.setMobilePhone(accountConsumer.getMobilePhone());

        if (null == accountConsumer.getId()) {
            AccountConsumer insertParam = new AccountConsumer();
            insertParam.setId(keyGenerateService.keyGenerate());
            // 原来是insertParam.setMobilePhone1(account.getMobilePhone1());
            insertParam.setMobilePhone(accountConsumer.getMobilePhone());
            insertParam.setOrgId(user.getOrgId());
            insertParam.setPostnId(user.getPostnId());
            insertParam.setCorpid(user.getCorpid());
            insertParam.setAcctName(StringUtils.isBlank(accountConsumer.getAcctName()) ? "门店客户" : accountConsumer.getAcctName());
            insertParam.setAcctType("ChannelConsumer");
            insertParam.setAcctStatus("Y");
            insertParam.setGender("UNKNOWN");
            insertParam.setAcctChannel("Store");
            insertParam.setAccntStage("PotentialConsumer");
            insertParam.setLogin(user.getUsername());
            // 原来是insertParam.setDataSource(account.getDataSource());
            insertParam.setSource(accountConsumer.getSource());
            this.insert(insertParam);
            return this.queryById(insertParam.getId());
        } else {
            return this.queryById(accountConsumer.getId());
        }
    }

    @Override
    public List<TagItem> queryTagsById(TagItem record) throws Exception {
        // 查询客户标签
        // 1. 如果客户没有关联企点客户,则只查询CRM标签
        // 2. 如果客户关联了企点客户,则通过客户id查询CRM标签,企点openId查询其关联的起点客户的企点标签
        return accountConsumerMapper.queryAccountTags(record);
    }

    @Override
    public void updateTagList(ListOfTags list) throws Exception {
        if (list.getList() != null && list.getList().size() > 0) {
            Long id;
            for (TagItem tagItem : list.getList()) {
                id = tagItem.getId();

                if (null == id) {
                    id = keyGenerateService.keyGenerate();
                    tagItem.setId(id);
                }
                // 客户自定义标签
                if ("other_accnt_tag".equals(tagItem.getSources())) {
                    if (ROW_STATUS_INSERT.equals(tagItem.getRow_status())) {
                        // 新建
                        accountConsumerMapper.accntTagInsert(tagItem);

                    } else if (ROW_STATUS_DELETE.equals(tagItem.getRow_status())) {
                        // 删除
                        accountConsumerMapper.deleteAccnt8TagById(tagItem);
                    }
                } else if ("CRM".equals(tagItem.getSources())) {
                    if (ROW_STATUS_INSERT.equals(tagItem.getRow_status())) {
                        // 新建
                        accountConsumerMapper.accntTagInsert(tagItem);

                    } else if (ROW_STATUS_DELETE.equals(tagItem.getRow_status())) {
                        // 删除
                        accountConsumerMapper.deleteAccnt8TagById(tagItem);
                    } else if (ROW_STATUS_UPDATE.equals(tagItem.getRow_status()) || StringUtils.isBlank(tagItem.getRow_status())) {
                        // 更新
                        accountConsumerMapper.accntTagUpdate(tagItem);
                    }
                }
            }
        }
    }

    @Override
    public List<TagItem> queryQdAccntTags(TagItem entity) throws Exception {
        return accountConsumerMapper.queryQdAccntTags(entity);
    }

    @Override
    public List<TagItem> queryQdAccntTagGroups(TagGroup entity) throws Exception {
        return accountConsumerMapper.queryQdAccntTagGroups(entity);
    }

    @Override
    public List<String> queryGuideList(AccountConsumer account) throws Exception {
        return accountConsumerMapper.queryGuideList(account);
    }

    @Override
    public void accountPersonInsert(AccountPerson entity) throws Exception {
        int count = accountConsumerMapper.queryAccountPersonById(entity);
        if (count == 0) {
            if (null == entity.getId()) {
                Long id = keyGenerateService.keyGenerate();
                entity.setId(id);
            }
            accountConsumerMapper.accountPersonInsert(entity);
        }
    }

    @Override
    public void emptyAccntSeq(AccountConsumer record) throws Exception {
        accountConsumerMapper.emptyAccntSeqUpdate(record);
    }

    @Override
    public AccountConsumer querySimpleAccntByWxOpenId(String wxOpenId) throws Exception {
        AccountConsumer entity = new AccountConsumer();
        entity.setMainWXOpenid(wxOpenId);
        return accountConsumerMapper.querySimpleAccntByWxOpenId(entity);
    }

    @Override
    public AccountConsumer queryConsumerByOpenId(AccountConsumer accountConsumer) throws Exception {
        return accountConsumerMapper.queryConsumerByOpenId(accountConsumer);
    }

    @Override
    public void addConsumer(AccountConsumer accountConsumer) throws Exception {
        // 在客户表增加记录
        accountConsumer.setId(keyGenerateService.keyGenerate());
        accountConsumer.setAcctType("ChannelConsumer");
        String createdDate = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
        accountConsumer.setCreated(createdDate);
        accountConsumer.setFirstEngageTime(createdDate);
        accountConsumer.setLastUpdated(createdDate);
        accountConsumer.setCreatedBy(accountConsumer.getId());
        accountConsumer.setLastUpdatedBy(accountConsumer.getId());
        accountConsumer.setAcctChannelType("MarketingPlatform");
        accountConsumerMapper.addConsumer(accountConsumer);
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public Map<String, Object> modifyConsumer(AccountConsumer account) throws Exception {
        Map<String, Object> result = new HashMap<>(16);
        LinkRedisClient  jedis = null;
        String unionId = null;
        try {
            jedis = RedisUtil.getJedis();
            // 将小程序票据code和加密id放到这integrateCode,integrationId字段中,不单开字段了
            String code = account.getIntegrateCode();
            String appEncryptionId = account.getIntegrationId();
            // 有从前端传入code和appEncryptionId,表示需要重新获取sessionkey
            if (StringUtils.isNotBlank(code) && StringUtils.isNotBlank(appEncryptionId)) {
                // 重置sessionKey
                JSONObject mpResult = this.resetSessionKey(jedis, code, appEncryptionId, account.getSessionKey());
                try {
                    // 尝试获取unionid
                    unionId = mpResult.getString("unionid");
                    account.setWxUnionid(unionId);
                } catch (Exception e) {
                    LCLogger.error().withMessageKey("mpLogin")
                            .withMessage("当前授权未获取到unionId").flush();
                }
            }

            // 处理数据
            String gender = account.getGender();
            String zero = "0";
            if (StringUtils.isNull(gender) || zero.equals(gender)) {
                account.setGender(null);
            } else {
                if (!genderMap.containsValue(gender)) {
                    gender = genderMap.get(gender);
                }
                account.setGender(gender);
            }
            String updateDate = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
            account.setLastUpdated(updateDate);
            // 如果unionId为空,则从加密信息中去获取unionId
            if (StringUtils.isBlank(unionId)) {
                // 解密数据
                String encryptData = account.getEncryptData();
                String sessionKey = account.getSessionKey();
                String iv = account.getIv();
                //日志信息
                String messageKey = "modifyConsumer";
                LCLogger.info().withMessageKey(messageKey)
                        .withMessage("小程序用户信息解密 encryptData =>" + encryptData
                                + ",session_key => " + sessionKey + ",iv => " + iv).flush();
                if (!StringUtils.isBlank(encryptData) && !StringUtils.isBlank(sessionKey) && !StringUtils.isBlank(iv)) {
                    JSONObject resultData = decryptData(sessionKey, encryptData, iv);
                    if (resultData != null) {
                        String unionIdKey = "unionId";
                        if (resultData.containsKey(unionIdKey)) {
                            unionId = resultData.getString(unionIdKey);
                            account.setWxUnionid(unionId);
                            String openid = account.getWxOwnOpenId();
                            if (StringUtils.isNotBlank(openid)) {
                                Subscriber subscriber = new Subscriber();
                                subscriber.setOpenid(openid);
                                subscriber.setPageFlag(false);
                                List<Subscriber> subscribers = wxSubscriberService.queryByExamplePage(subscriber);
                                if (subscribers.size() == 1) {
                                    subscriber = subscribers.get(0);
                                    if (StringUtils.isBlank(subscriber.getUnionid())) {
                                        subscriber.setUnionid(unionId);
                                        wxSubscriberService.update(subscriber);
                                    }
                                }

                            }
                        }
                    }
                }
            }
            // 如果filterType为account,则更新客户信息,否则不更新
            if ("account".equals(account.getFilterType())) {
                // 更新或新建消费者
                checkChannelConsumerForUpdate(account);
            }
            Subscriber subscriber = updateSubscriberInfo(account);
            CoreUser user = UserUtil.getUser();
            user.setWxUnionId(subscriber.getUnionid());
            SecurityInterceptor.tempUser.set(user);
            accountConsumerMapper.modifyConsumer(account);
            result.put("account", account);
            result.put("subscriber", subscriber);
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    @Override
    public Subscriber updateSubscriberInfo(AccountConsumer accountConsumer) throws Exception {
        // 更新微信订阅者表
        Subscriber subscriber = wxSubscriberService.queryByOpenId(accountConsumer.getWxOwnOpenId());
        if (subscriber == null) {
            subscriber = new Subscriber();
            subscriber.setRow_status(ROW_STATUS_INSERT);
            subscriber.setId(keyGenerateService.keyGenerate());
            subscriber.setOpenid(accountConsumer.getWxOwnOpenId());
        }
        subscriber.setSex(accountConsumer.getGender());
        subscriber.setNickname(accountConsumer.getWxNickname());
        subscriber.setHeadimgurl(accountConsumer.getWxHeadimgurl());
        subscriber.setCountry(accountConsumer.getCountry());
        subscriber.setProvince(accountConsumer.getProvince());
        subscriber.setCity(accountConsumer.getCity());
        subscriber.setLanguage(accountConsumer.getWxLanguage());
        subscriber.setSource("MiniProgram");
        subscriber.setUnionid(accountConsumer.getWxUnionid());

        CoreUser user = UserUtil.getUser();
        if (user != null) {
            subscriber.setWxAppId(user.getMpAppId());
        }
        if (ROW_STATUS_INSERT.equals(subscriber.getRow_status())) {
            wxSubscriberService.insert(subscriber);
        } else {
            wxSubscriberService.update(subscriber);
        }
        return subscriber;
    }

    @Override
    public Map<String, Object> decryptWxData(AccountConsumer record) throws Exception {
        Map<String, Object> result = new HashMap<>();
        LinkRedisClient  jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            String sessionKey = record.getSessionKey();
            String encryptData = record.getEncryptData();
            String iv = record.getIv();
            result = decryptData(sessionKey, encryptData, iv);
            if (null == result) {
                throw new ServiceException("ACCT-013");
            }
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    @Override
    public List<AccountConsumer> queryAcctListById(AccountConsumer entity) throws Exception {
        if (null == entity) {
            throw new ServiceException("ACCT-014");
        }
        List<AccountConsumer> accountList = new ArrayList<>();
        try {
            String queryType = "mobilePhone";
            AccountConsumer account = new AccountConsumer();
            account.setPageFlag(false);
            boolean flag = queryType.equals(entity.getAttr1());
            // 根据会员查消费者
            if (null != entity.getMemberId() && !flag) {
                account.setMemberId(entity.getMemberId());
                accountList = accountConsumerMapper.queryByExamplePage(account);
                // 根据电话号码查消费者
                // 原来是} else if (StringUtils.isNotBlank(entity.getMobilePhone1()) && flag) {
                // account.setMobilePhone1(entity.getMobilePhone1());
            } else if (StringUtils.isNotBlank(entity.getMobilePhone()) && flag) {
                account.setMobilePhone(entity.getMobilePhone());
                accountList = accountConsumerMapper.queryByExamplePage(account);
            } else {
                accountList.add(entity);
            }
        } catch (Exception e) {
            LCLogger.withException(e);
            throw new Exception(e.getMessage());
        }
        return accountList;
    }

    @Override
    @Transactional(rollbackFor = BasicServiceException.class)
    public Map<String, Object> updMobilePhoneInfo(AccountConsumer record) throws Exception {
        Map<String, Object> result = new HashMap<>(2);
        CoreUser user = UserUtil.getUser();
        // 根据手机号码和渠道查询消费者
        AccountConsumer account = new AccountConsumer();
        // 原来是account.setMobilePhone1(record.getMobilePhone());
        account.setMobilePhone(record.getMobilePhone());
        account.setAcctChannel(user.getMpAppId());
        List<AccountConsumer> accountList = accountConsumerMapper.queryByExamplePage(account);
        if (accountList != null && accountList.size() > 0) {
            // 如果存在，判断是否与当前用户为同一条记录
            if (user.getAcctId().equals(accountList.get(0).getId())) {
                result.put("result", "Y");
                result.put("message", "该手机号已绑定此微信号");
            } else {
                result.put("result", "N");
                result.put("message", "该手机号已绑定其他微信号");
            }
        } else {
            // 不存在，更新当前用户
            AccountConsumer newAccount = this.queryById(user.getAcctId());
            // 原来是newAccount.setMobilePhone1(record.getMobilePhone());
            newAccount.setMobilePhone(record.getMobilePhone());
            accountConsumerMapper.updMobilePhoneInfo(newAccount);
            result.put("result", "Y");
            result.put("message", "已更新");
        }
        return result;
    }

    @Override
    public AccountConsumer queryAcctAndMember(AccountConsumer entity) throws Exception {
        return accountConsumerMapper.queryAcctAndMember(entity);
    }

    @Override
    public Map<String, Object> checkMpLoginPhone(AccountConsumer record) throws Exception {
        Map<String, Object> result = new HashMap<>(2);
        String mobilePhone = record.getMobilePhone();
        AccountConsumer accountParam = new AccountConsumer();
        // 原来是accountParam.setMobilePhone1(mobilePhone);
        accountParam.setMobilePhone(mobilePhone);
        accountParam.setAcctType("ChannelConsumer");
        accountParam.setAcctChannelType("MiniProgram");
        accountParam.setPageFlag(false);
        List<AccountConsumer> accountList = this.queryByExamplePage(accountParam);
        // 逻辑有问题 后续考虑更改，先保证逻辑能走通
/*        if (accountList.size() > 0) {
            // 如果存在，应该只存在一条这样的记录。判断openid是否相同
            String openid = UserUtil.getUser().getOpenId();
            String openidData = accountList.get(0).getWxOwnOpenId();
            if (openid.equals(openidData)) {
                result.put("result", "Y");
            } else {
                result.put("result", "N");
                result.put("failMessage", "该手机号已绑定其他微信");
            }
        } else {
            // 不存在，判断当前用户是否之前保存有手机号码信息
            Long id = UserUtil.getUser().getId();
            AccountConsumer account = this.queryById(id);
            if (StringUtils.isBlank(account.getMobilePhone1())) {
                // 更新信息
                account.setMobilePhone1(mobilePhone);
                this.update(account);
                result.put("result", "Y");
            } else {
                if (mobilePhone.equals(account.getMobilePhone1())) {
                    result.put("result", "Y");
                } else {
                    result.put("result", "N");
                    result.put("failMessage", "该微信已绑定其他手机号");
                }
            }
        }*/
        if (accountList.size() > 0) {
            result.put("result", "Y");
        }
        return result;
    }

    @Override
    public AccountConsumer saveAccountToDmp(AccountConsumer entity) throws Exception {
        String dmpConsumerUrl = "http://" + YmlConstants.getDmpIp() + DMP_CONSUMER_INTERFACE_URL;
        if (StringUtils.isBlank(entity.getId() + "")) {
            entity.setId(keyGenerateService.keyGenerate());
        }
        // 调用DMP接口新增渠道消费者
        String channelConsumer = "ChannelConsumer";
        entity.setConsumerType(channelConsumer);
        // 处理标签数据组装长文本
        ListOfTags listOfTags = entity.getListOfTags();
        if (listOfTags != null) {
            List<TagItem> list = CollectionUtils.isEmpty(listOfTags.getList()) ? new ArrayList<>(0) : listOfTags.getList();
            StringBuilder sb = new StringBuilder();
            for (int i = 0, size = list.size(); i < size; i++) {
                // 前端组件中，自定义标签名存在ID中
                sb.append(list.get(i).getTagId());
                if (i != size - 1) {
                    sb.append("&");
                }
            }
            entity.setxAttr70(sb.toString());
        }
        JSONObject param = JSONObject.parseObject(JSONObject.toJSONString(transformToDmpConsumer(entity)));
        logger.info("Base [消费者]传入接口参数：" + param.toString());
        Map<String, Object> jsonObject = SecretKeyUtil.dmpHttpPostWithDefault(dmpConsumerUrl, param);
        logger.info("DMP [消费者]返回数据：" + jsonObject.toString());
        JSONObject message = null;
        try {
            message = JSONObject.parseObject(jsonObject.get("message").toString());
        } catch (Exception e) {
            logger.error("DMP系统连接失败，当前URL为【" + dmpConsumerUrl + "】");
            throw new BasicServiceException("DMP系统连接失败，当前URL为【" + dmpConsumerUrl + "】");
        }
        boolean requestFail = !(boolean) jsonObject.get("success") || !(boolean) message.get("success");
        if (requestFail) {
            logger.error("DMP系统保存消费者失败：" + message.get("result"));
            throw new BasicServiceException("DMP系统保存消费者失败：" + message.get("result"));
        }
        JSONObject newRowJson = (JSONObject) message.get("newRow");
        AccountConsumer newRow = transformDmpToLink(newRowJson);
        AccountConsumer account = queryById(newRow);
        if (account != null) {
            // 营销平台已存在记录，仅更新，当DMP返回数据为未更新的数据时，此时可以同步DMP与营销平台的数据
            this.update(newRow);
        } else {
            this.insert(newRow);
        }
        // 保存父消费者
        JSONObject parentRowJson = (JSONObject)message.get("parentRow");
        if (parentRowJson != null) {
            AccountConsumer parentRow = transformDmpToLink(parentRowJson);
            if (queryById(parentRow) == null) {
                parentRow.setRow_status(BasicService.ROW_STATUS_INSERT);
                this.upsert(parentRow);
            }
        }
        return newRow;
    }

    @Override
    public AccountConsumer checkChannelConsumer(AccountConsumer entity) throws Exception {
        logger.info("Base checkChannelConsumer：");
        logger.info(JSONObject.toJSON(entity));
        List<AccountConsumer> accounts = searchAccountsBySourceType(entity);
        if (!CollectionUtils.isEmpty(accounts)) {
            return accounts.get(0);
        }
        // 需要新建
        entity.setRow_status(BasicService.ROW_STATUS_INSERT);
        /* 当判断为新增时，可能从前端带来一个原有消费者对象的ID，
         * 会在DMP系统抛出主键重复异常，故使ID置空
         */
        entity.setId(Long.parseLong("0"));
        return this.saveAccountToDmp(entity);
    }

    @Override
    public AccountConsumer checkChannelConsumerForUpdate(AccountConsumer entity) throws Exception {
        List<AccountConsumer> accounts = searchAccountsByMobileCompanyChannel(entity);
        if (!CollectionUtils.isEmpty(accounts)) {
            AccountConsumer notModify = new AccountConsumer();
            BeanUtils.copyProperties(entity, notModify);
            entity = accounts.get(0);
            entity.setRow_status(BasicService.ROW_STATUS_UPDATE);
            updateFieldSelective(entity, notModify);
        } else {
            entity.setRow_status(BasicService.ROW_STATUS_INSERT);
            /* 当判断为新增时，可能从前端带来一个原有消费者对象的ID，
             * 会在DMP系统抛出主键重复异常，故使ID置空
             */
            entity.setId(Long.parseLong("0"));
        }
        // 需要新建
        return this.saveAccountToDmp(entity);
    }

    @Override
    public void updateConsumer(AccountConsumer entity) throws Exception {
        accountConsumerMapper.updateConsumer(entity);
    }

    @Override
    public AccountConsumer queryConsumerById(Long id) throws Exception {
        return accountConsumerMapper.queryConsumerById(id);
    }

    @Override
    public AccountConsumer wxUpdateAccount(AccountConsumer account) throws Exception {
        accountConsumerMapper.wxUpdateAccount(account);
        return accountConsumerMapper.queryById(account);
    }

    @Override
    public AccountConsumer newConsumerByPhone(AccountConsumer entity) throws Exception {
        if (StringUtils.isBlank(entity.getAcctChannel())) {
            entity.setAcctChannel(ACCOUNT_CHANNEL_MARKETING);
        }

        if (StringUtils.isBlank(entity.getAcctChannelType())) {
            entity.setAcctChannelType(ACCOUNT_CHANNEL_TYPE_MARKETING_PLATFORM);
        }

        AccountConsumer record = accountConsumerMapper.queryUniqueByPhone(entity);
        //消费者不存在时，创建消费者
        if (null != record) {
            return record;
        }

        if (StringUtils.isBlank(entity.getAcctType())) {
            entity.setAcctType("ChannelConsumer");
        }
        if (StringUtils.isBlank(entity.getAcctStatus())) {
            entity.setAcctStatus("Y");
        }

        entity.setFirstEngageTime(DateUtil.dateToStr(new Date(), DateUtil.DATE_TIME));

        CoreUser user = UserUtil.getUser();
        entity.setOrgId(user.getOrgId());
        entity.setPostnId(user.getPostnId());

        insert(entity);
        return queryById(entity);
    }

    @Override
    public void consumerUpdate(AccountConsumer entity) throws Exception {
        accountConsumerMapper.consumerUpdate(entity);
    }

    @Override
    public Map<String, Object> queryConsumerTag(Long uniqueConsumerId) throws Exception {
        JSONObject requestPayload = new JSONObject();
        requestPayload.put("searchParam", "cdc_con_tag");
        requestPayload.put("searchValue", uniqueConsumerId);
        Map<String, Object> response = cdcPubConsumerClient.queryComInfoByPage(requestPayload).getInnerMap();

        String successKey = "success";
        if (!(Boolean)response.get(successKey)) {
            return response;
        }

        // 标准标签查询标签名并设置值
        Object rows = response.getOrDefault("rows", "");
        List<JSONObject> consumerTags = JSON.parseArray(JSON.toJSONString(rows), JSONObject.class);
        // 标准标签判断方法
        Predicate<JSONObject> isStandardTag = e -> "Standard".equals(e.getString("tag_type"));
        // 按照是否标准标签分组消费者标签列表
        Map<Boolean, List<JSONObject>> partitionConsumerTags = consumerTags.parallelStream().collect(partitioningBy(isStandardTag, toList()));
        for (JSONObject stdTag : partitionConsumerTags.get(true)) {
            Long tagId = stdTag.getLong("tag_id");
            PortalAccntTagItem tagItem = portalAccntTagItemService.queryById(tagId);
            String tagName = Optional.ofNullable(tagItem).map(PortalAccntTagItem::getTagName).orElse("");
            stdTag.put("tag_value", tagName);
        }
        // 非标准标签添加到标准标签列表
        partitionConsumerTags.get(true).addAll(partitionConsumerTags.get(false));
        // 替换处理后的标签列表
        response.put("rows", partitionConsumerTags.get(true));
        return response;
    }

    @Override
    public List<AccountConsumer> queryConsumerByCondition(AccountConsumer accountConsumer) throws Exception {
        return accountConsumerMapper.queryConsumerByCondition(accountConsumer);
    }

    private void setAccountSubObjectList(AccountConsumer account) throws Exception {
        // 地址列表
        AcctAddress acctAddress = new AcctAddress();
        acctAddress.setAcctId(account.getId());
        List<AcctAddress> acctAddressList = acctAddressService.queryAll(acctAddress);
        account.setAddrList(acctAddressList);
        // 导购列表
        List<String> guides = queryGuideList(account);
        account.setGuides(guides);
        // 标签列表
        ListOfTags listOfTags = new ListOfTags();
        listOfTags.setAccountId(account.getId());
        TagItem tagItem = new TagItem();
        tagItem.setAccntRowId(account.getId());
        listOfTags.setList(queryTagsById(tagItem));
        // 需要看一下用哪个标签列表
        account.setListOfTags(listOfTags);
    }

    /**
     * 重置redis中的sessionkey的值
     *
     * @author LiQun
     * @param jedis           jedis实例
     * @param code            票据
     * @param appEncryptionId app加密id
     * @param session_key     自定义的key
     * @date 2019/3/28 14:44
     */
    private JSONObject resetSessionKey(LinkRedisClient jedis, String code, String appEncryptionId, String session_key) throws Exception {
        Mp mp = userService.getMpConfigInfo(jedis, appEncryptionId);
        String mpAppId = mp.getAppId();
        String mpAppSecret = mp.getAppSecret();
        String mpCorpId = mp.getCorpid() + "";
        if (StringUtils.isBlank(mpAppId) || StringUtils.isBlank(mpAppSecret) || StringUtils.isBlank(mpCorpId)) {
            throw new BasicServiceException("获取小程序参数信息异常!");
        }
        // 获取openId,unionid,sessionkey信息
        JSONObject mpResult = userService.getJsCodeToSession(code, mpAppId, mpAppSecret);
        if (mpResult == null) {
            throw new BasicServiceException("调用微信接口返回信息为空，请检查");
        } else {
            String errcode = "errcode";
            if (mpResult.get(errcode) != null) {
                String errorResult = mpResult.getString("errmsg");
                throw new BasicServiceException(errorResult);
            } else {
                // 会话密钥
                String sessionKey = mpResult.getString("session_key");
                // 将redis中的值重置
                jedis.hset(session_key, "sessionKey", sessionKey);
                jedis.expire(session_key, 7200);
            }
        }
        return mpResult;
    }

    /**
     * 微信加密数据解密
     *
     * @author KuangRuifeng
     * @date 2018年11月29日
     * @param sessionKey session_key
     * @param encryptData 加密数据
     * @param iv 加密算法的初始向量
     * @return result 解密之后json数据
     */
    private JSONObject decryptData(String sessionKey, String encryptData, String iv) {
        LinkRedisClient j = null;
        String sessionKeyTemp = "";
        JSONObject result = null;
        try {
            j = RedisUtil.getJedis();
            sessionKeyTemp = j.hget(sessionKey, "sessionKey");
            LCLogger.info().withMessage("Redis中session_key => " + sessionKeyTemp).flush();
        } finally {
            RedisUtil.returnResource(j);
        }
        if (!StringUtils.isBlank(sessionKeyTemp)) {
            try {
                byte[] resultByte = PasswordUtil.decrypt(org.apache.commons.codec.binary.Base64.decodeBase64(encryptData),
                        org.apache.commons.codec.binary.Base64.decodeBase64(sessionKeyTemp),
                        org.apache.commons.codec.binary.Base64.decodeBase64(iv));
                if (null != resultByte && resultByte.length > 0) {
                    String infoStr = new String(resultByte, "UTF-8");
                    LCLogger.info().withMessage("userInfoStr => " + infoStr).flush();
                    result = JsonUtil.toJsonObject(infoStr);
                } else {
                    LCLogger.info().withMessage("解密失败").flush();
                }
            } catch (InvalidAlgorithmParameterException | UnsupportedEncodingException e) {
                LCLogger.withException(e);
            }
        } else {
            LCLogger.info().withMessage("未匹配到redis记录").flush();
        }
        return result;
    }

    /**
     * 将DMP数据转化为link的对象
     *
     * @author NingLanhao
     * @date 2019-04-07 18:27
     * @param jsonObj
     * @return com.link.business.base.accnt.model.Account
     */
    private AccountConsumer transformDmpToLink(JSONObject jsonObj) {
        AccountConsumer obj = new AccountConsumer();
        Class<AccountConsumer> accountClass = AccountConsumer.class;
        Field[] fields = accountClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(DmpField.class)) {
                // link字段名
                String name = field.getName();
                // 对应set方法
                String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
                DmpField annotation = field.getAnnotation(DmpField.class);
                // dmp对应字段名，作为map的KEY
                String linkFieldName = annotation.fieldName();
                Object valueObj = jsonObj.get(linkFieldName);
                if (valueObj != null) {
                    // dmp字段值
                    String value = valueObj.toString();
                    try {
                        Method method = accountClass.getMethod(methodName, String.class);
                        method.invoke(obj, new Object[]{value});
                    } catch (NoSuchMethodException e) {
                        throw new BasicServiceException("不存在【" + methodName + "】此方法");
                    } catch (IllegalAccessException e) {
                        throw new BasicServiceException("【" + methodName + "】方法执行失败");
                    } catch (InvocationTargetException e) {
                        throw new BasicServiceException("【" + methodName + "】方法执行失败");
                    }
                }
            }
        }
        obj.setId(Long.parseLong(jsonObj.get("id").toString()));
        obj.setOrgId(Long.parseLong(jsonObj.get("orgId").toString()));
        obj.setPostnId(Long.parseLong(jsonObj.get("postnId").toString()));
        return obj;
    }

    /**
     * 将link中的Account对象做字段映射，提供调用DMP接口的消费者参数
     *
     * @author NingLanhao
     * @param entity 新增客户参数
     * @date 2019-03-26 17:06
     */
    private Object transformToDmpConsumer(AccountConsumer entity) {
        CoreUser user = UserUtil.getUser();
        Map<String, Object> param = new HashMap<>(30);
        // 标准字段
        param.put("id", entity.getId());
        String orgId = StringUtils.isBlank(entity.getOrgId() + "") ? user.getOrgId() + "" : entity.getOrgId() + "";
        String postnId = StringUtils.isBlank(entity.getPostnId() + "") ? user.getPostnId() + "" : entity.getPostnId() + "";
        if (StringUtils.isBlank(orgId) || StringUtils.isBlank(postnId)) {
            throw new BasicServiceException("请联系管理员维护组织或职位信息");
        }
        param.put("orgId", orgId);
        param.put("postnId", postnId);
        param.put("row_status", entity.getRow_status());
        param.put("srcRowId", entity.getId());
        param.put("srcCreated", entity.getCreated());
        param.put("srcCreatedBy", entity.getCreatedBy());
        param.put("srcLastUpd", entity.getLastUpdated());
        param.put("srcLastUpdBy", entity.getLastUpdatedBy());
        // 已经做过映射的字段
        SecretKeyUtil.DmpParamUtil.transformDmpAnnotationField(entity, param);

        return param;
    }

    /**
     *  消费者查询,根据来源类型决定手机号或者OPENID的查询条件
     *
     * @author NingLanhao
     * @date 2019-04-04 15:18
     * @param entity
     * @return java.util.List
     */
    private List<AccountConsumer> searchAccountsBySourceType(AccountConsumer entity) throws Exception {
        //原来是String mobilePhone1 = entity.getMobilePhone1();
        String mobilePhone1 = entity.getMobilePhone();
        Long companyId = entity.getCompanyId();
        String acctChannel = entity.getAcctChannel();
        boolean checkConditionIsLess =  companyId == null
                || StringUtils.isBlank(acctChannel);
        if (checkConditionIsLess) {
            throw new BasicServiceException("渠道消费者查询条件缺失");
        }
        List<Filter> list = new ArrayList<Filter>();
        list.add(new Filter("companyId", String.valueOf(companyId)));
        list.add(new Filter("acctType", "ChannelConsumer"));
        list.add(new Filter("acctChannel", acctChannel));
        list.add(new Filter("consumerType", "ChannelConsumer"));
        if (SOURCE_CHANNEL_MARKET.equals(acctChannel)) {
            list.add(new Filter("mobilePhone1", mobilePhone1));
        } else if (SOURCE_CHANNEL_WE_CHAT.equals(acctChannel)) {
            list.add(new Filter("wxOwnOpenId", entity.getWxOwnOpenId()));
        }
        AccountConsumer queryParam = (AccountConsumer) QueryParamUtil.addQpsFilter(Account.class, false, (Filter[])list.toArray(new Filter[0]));
        return this.queryByExamplePage(queryParam);
    }

    /**
     *  消费者查询
     *
     * @author NingLanhao
     * @date 2019-04-04 15:18
     * @param entity  1.手机号 2.公司ID 3.消费者渠道
     * @return java.util.List
     */
    private List<AccountConsumer> searchAccountsByMobileCompanyChannel(AccountConsumer entity) throws Exception {
        //原来是String mobilePhone1 = entity.getMobilePhone1();
        String mobilePhone = entity.getMobilePhone();
        Long companyId = entity.getCompanyId();
        String acctChannel = entity.getAcctChannel();
        boolean checkConditionIsLess =  companyId == null
                || StringUtils.isBlank(acctChannel);
        if (checkConditionIsLess) {
            throw new BasicServiceException("渠道消费者查询条件缺失");
        }
        List<Filter> list = new ArrayList<Filter>();
        list.add(new Filter("companyId", String.valueOf(companyId)));
        list.add(new Filter("acctType", "ChannelConsumer"));
        list.add(new Filter("acctChannel", acctChannel));
        list.add(new Filter("consumerType", "ChannelConsumer"));
        //原来是if (StringUtils.isNotBlank(mobilePhone1)) {
        if (StringUtils.isNotBlank(mobilePhone)) {
            //原来是list.add(new Filter("mobilePhone1", mobilePhone1));
            list.add(new Filter("mobilePhone", mobilePhone));
        }
        AccountConsumer queryParam = (AccountConsumer) QueryParamUtil.addQpsFilter(Account.class, false, (Filter[])list.toArray(new Filter[0]));
        return this.queryByExamplePage(queryParam);
    }

    /**
     * 仅修改指定字段字段
     *
     * @author NingLanhao
     * @date 2019-04-04 16:46
     * @param old 数据库内原始对象
     * @param notModify 接口传入对象，要保存的信息
     * @return void
     */
    private void updateFieldSelective(AccountConsumer old,AccountConsumer notModify) {
        old.setAcctName(notModify.getAcctName());
        old.setGender(notModify.getGender());
        old.setBirthday(notModify.getBirthday());
        old.setWxOwnOpenId(notModify.getWxOwnOpenId());
        if (StringUtils.isBlank(old.getSalesmanId() + "")) {
            old.setSalesmanId(notModify.getSalesmanId());
            old.setPostnId(notModify.getPostnId());
            old.setOrgId(notModify.getOrgId());
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        genderMap.put("0", "UNKNOWN");
        genderMap.put("1", "MALE");
        genderMap.put("2", "FEMALE");
    }
}